package org.example.rowing.controller.raceProcessController;

import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.example.rowing.domain.RegistrationWithAthlete;
import org.example.rowing.domain.Team;
import org.example.rowing.service.*;
import org.example.rowing.vo.RegistrationVO;
import org.example.rowing.vo.RoundScoreVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Collectors;

@Controller
@Slf4j
public class CKDrawLotteryController {

    @FXML
    public Button cancelButton;
    @FXML
    public Button drawButton;
    @FXML
    public Button exportButton;
    @FXML
    private ListView<RegistrationVO> teamListView;  // 显示队伍列表
    @FXML
    private ListView<String> laneListView;  // 显示航道分配
    @FXML
    private Button confirmButton;

    private List<RegistrationVO> teamList = new ArrayList<>(); // 保存所有队伍

    private List<String> lanes;
    private Map<RegistrationVO, String> laneAssignments = new HashMap<>(); // 保存航道分配结果
    @Setter
    private Consumer<String> confirmCallback;
    private Long raceId;

    @Autowired
    private RaceProcessCommonService raceProcessCommonService;
    @Autowired
    private CKDrawLotteryService drawLotteryService;
    @Autowired
    private RaceInfoService raceInfoService;
    @Autowired
    private RegistrationInfoService registrationInfoService;


    // 初始化界面，加载队伍和航道
    @FXML
    public void initialize(Long raceId) {
        this.raceId = raceId;
        // 加载队伍列表
        teamList.clear();
        laneAssignments.clear();
        teamList = raceProcessCommonService.getRegistrationVOByRaceId(raceId);// 假设该方法从服务中获取队伍列表
        // 根据队伍数量，选择需要使用的赛道
        lanes = generateDynamicLanes(teamList.size());

        // 设置转换器，使下拉框只显示 name
        teamListView.setCellFactory(lv -> new ListCell<RegistrationVO>() {
            @Override
            protected void updateItem(RegistrationVO item, boolean empty) {
                super.updateItem(item, empty);
                setText(empty || item == null ? "" : item.getTeam().getName() + "-" + item.getRegistrationId());
            }
        });

        teamListView.getItems().addAll(teamList);

        // 尝试加载上一次抽签结果
        Map<RegistrationVO, String> previousResult = drawLotteryService.getLotteryResult(raceId, teamList.size());
        laneListView.getItems().clear();
        if (previousResult != null && !previousResult.isEmpty()) {
            laneAssignments.putAll(previousResult);
            // 展示格式：队伍名称 -> 航道编号
            laneListView.getItems().addAll(
                    laneAssignments.entrySet().stream()
                            .map(entry -> entry.getKey().getTeam().getName() + "-" + entry.getKey().getRegistrationId() + " -> " + entry.getValue())
                            .toList()
            );
        } else {
            // 没有上次结果，则显示所有航道供用户参考
            laneListView.getItems().addAll(lanes);
        }

        if (arePreliminaryScoresEntered()) {
            showInfoDialog("比赛已开始，抽签功能已禁用！");
            drawButton.setDisable(true);
            confirmButton.setDisable(true);
        }
    }

    public List<String> generateDynamicLanes(int teamCount) {
        List<String> lanes = new ArrayList<>();
        if (teamCount <= 0) return lanes;

        // 1. 计算分组数量 (向上取整)
        int groupCount = (int) Math.ceil(teamCount / 9.0);

        // 2. 定义赛道占用优先级顺序
        final int[] LANE_PRIORITY = {5, 4, 6, 3, 7, 2, 8, 1, 9};

        // 3. 计算每组分配的赛艇数量
        int base = teamCount / groupCount;
        int remainder = teamCount % groupCount;

        // 4. 遍历每个组生成赛道
        for (int groupIndex = 0; groupIndex < groupCount; groupIndex++) {
            // 4.1 确定当前组分配的赛艇数量
            int groupSize = base + (groupIndex < remainder ? 1 : 0);

            // 4.2 生成组名 (A组、B组...)
            char groupName = (char) ('A' + groupIndex);

            // 4.3 按优先级顺序生成当前组的赛道
            for (int i = 0; i < groupSize; i++) {
                if (i >= LANE_PRIORITY.length) {
                    throw new IllegalArgumentException("单组赛艇数量超过9条的限制");
                }
                int laneNumber = LANE_PRIORITY[i];
                lanes.add(groupName + "组" + laneNumber + "号");
            }
        }

        return lanes;
    }

    /**
     * 辅助方法：检查预赛成绩是否已录入
     */
    private boolean arePreliminaryScoresEntered() {
        List<RoundScoreVO> roundScoreVOS = raceInfoService.loadRoundScoreVOByRaceId(raceId);
        for (RoundScoreVO roundScoreVO : roundScoreVOS) {
            if (roundScoreVO.getScore() != null)
                return true;
        }
        return false;
    }

    // 抽签按钮的事件处理
    @FXML
    private void handleDrawButtonClick() {
        if (teamList.isEmpty() || lanes.isEmpty()) {
            showErrorDialog("队伍或航道不足，无法进行抽签！");
            return;
        }
        // 打乱队伍列表
        Collections.shuffle(teamList);
        // 清空航道分配
        laneAssignments.clear();
        // 将队伍分配到航道
        for (int i = 0; i < teamList.size(); i++) {
            RegistrationVO registrationVO = teamList.get(i);
            String lane = lanes.get(i);  // 假设每个队伍占用一个航道
            laneAssignments.put(registrationVO, lane);
        }
        // 更新航道分配列表
        laneListView.getItems().clear();
        laneListView.getItems().addAll(laneAssignments.entrySet().stream()
                .map(entry -> entry.getKey().getTeam().getName() + "-" + entry.getKey().getRegistrationId() + " -> " + entry.getValue())
                .toList());

        log.info("抽签完成，队伍已分配到航道！");
    }

    // 确认按钮的事件处理
    @FXML
    private void handleConfirmButtonClick() {
        // 确认分配结果
        log.info("航道分配已确认：{}", laneAssignments);
        drawLotteryService.saveLotteryResult(laneAssignments, raceId, teamList.size());
        showInfoDialog("抽签完成，队伍已成功分配到航道！");
        // 将抽签结果传回调用方（例如主界面）
        if (confirmCallback != null) {
            confirmCallback.accept("预赛");
        }
        Stage stage = (Stage) confirmButton.getScene().getWindow();
        stage.close();
    }

    public void handleCancelButtonClick() {
        // 执行取消操作，例如关闭当前窗口或重置界面状态
        log.info("抽签操作已取消。");
        // 示例：关闭当前窗口
        Stage stage = (Stage) cancelButton.getScene().getWindow();
        stage.close();
    }

    // 弹出错误提示框
    private void showErrorDialog(String message) {
        Alert alert = new Alert(Alert.AlertType.ERROR);
        alert.setTitle("错误");
        alert.setHeaderText(null);
        alert.setContentText(message);
        alert.showAndWait();
    }

    // 弹出信息提示框
    private void showInfoDialog(String message) {
        Alert alert = new Alert(Alert.AlertType.INFORMATION);
        alert.setTitle("信息");
        alert.setHeaderText(null);
        alert.setContentText(message);
        alert.showAndWait();
    }

    @FXML
    public void handleExportButtonClick(ActionEvent event) {
        // 1. 弹出文件保存对话框
        FileChooser fileChooser = new FileChooser();
        fileChooser.setTitle("保存抽签结果");
        fileChooser.setInitialFileName("预赛航道分配抽签结果.xlsx");
        fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("Excel 文件", "*.xlsx"));
        File file = fileChooser.showSaveDialog(exportButton.getScene().getWindow());
        if (file == null) {
            return; // 用户取消或未选择文件
        }

        // 2. 创建 Workbook 和 Sheet
        Workbook workbook = new XSSFWorkbook();
        Sheet sheet = workbook.createSheet("抽签结果");

        // 3. 从 laneAssignments 中解析航道编号，并建立 “航道编号 -> 队伍” 的映射
        //    laneAssignments: Map<teamName, laneString>  例如：{"西安队" -> "A组3号"}
        //    目标：构造一个按航道排序的结构，比如： A组3号 -> "西安队"
        //    如果一个航道上可能有多支队伍，则可改为 Map<Integer, List<String>>。
        Map<String, RegistrationVO> laneToTeamMap = new TreeMap<>();  // 按航道编号升序排列
        String raceName = "";
        for (Map.Entry<RegistrationVO, String> entry : laneAssignments.entrySet()) {
            RegistrationVO registrationVO = entry.getKey();// 队伍名称
            String laneStr = entry.getValue();   // 如 "A组3号"
            raceName = registrationVO.getRace().getName();
            laneToTeamMap.put(laneStr, registrationVO);
        }

        // 设置字体样式
        CellStyle headerStyle = workbook.createCellStyle();
        Font headerFont = workbook.createFont();
        headerFont.setBold(true);
        headerFont.setFontHeightInPoints((short)12);
        headerStyle.setFont(headerFont);
        headerStyle.setAlignment(HorizontalAlignment.CENTER);

        // 第一行：项目名称（合并单元格）
        Row row0 = sheet.createRow(0);
        org.apache.poi.ss.usermodel.Cell cell00 = row0.createCell(0);
        cell00.setCellValue(raceName);
        cell00.setCellStyle(headerStyle);
        sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, 3));

        // 第二行：导出日期
        String exportDate = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy.MM.dd"));
        Row row1 = sheet.createRow(1);
        org.apache.poi.ss.usermodel.Cell cell10 = row1.createCell(0);
        cell10.setCellValue("导出时间：" + exportDate);

        // 第三行：比赛轮次
        Row row2 = sheet.createRow(2);
        org.apache.poi.ss.usermodel.Cell cell20 = row2.createCell(0);
        cell20.setCellValue("当前轮次：预赛");

        // 5. 写入第四行：航道
        Row rowLane = sheet.createRow(3);
        // 第 0 列写“航道”
        rowLane.createCell(0).setCellValue("航道");

        // 6. 写入第五行：姓名
        Row rowName = sheet.createRow(4);
        rowName.createCell(0).setCellValue("姓名");

        // 7. 写入第六行：号码
        Row rowNumber = sheet.createRow(5);
        rowNumber.createCell(0).setCellValue("号码");

        // 8. 写入第七行：代表队
        Row rowTeam = sheet.createRow(6);
        rowTeam.createCell(0).setCellValue("代表队");

        // 8. 写入第八行：报名编号
        Row rowRegistration = sheet.createRow(7);
        rowRegistration.createCell(0).setCellValue("报名编号");

        // 9. 按照 laneToTeamMap 的顺序依次将航道信息写入到列 1、2、3... 中
        int colIndex = 1; // 从第 1 列开始写
        for (Map.Entry<String, RegistrationVO> entry : laneToTeamMap.entrySet()) {
            String laneNumber = entry.getKey();
            RegistrationVO registrationVO = entry.getValue();

            // 航道
            rowLane.createCell(colIndex).setCellValue(laneNumber);

            // 姓名（用“、”连接）
            List<RegistrationWithAthlete> athletes = registrationVO.getAthletes();
            String joinedNames = athletes.stream()
                    .map(RegistrationWithAthlete::getAthleteName)
                    .collect(Collectors.joining("、"));
            rowName.createCell(colIndex).setCellValue(joinedNames);

            // 号码（用“、”连接）
            String joinedNumbers = athletes.stream()
                    .map(RegistrationWithAthlete::getAthleteNum)
                    .collect(Collectors.joining("、"));
            rowNumber.createCell(colIndex).setCellValue(joinedNumbers);

            // 代表队
            rowTeam.createCell(colIndex).setCellValue(registrationVO.getTeam().getName());

            rowRegistration.createCell(colIndex).setCellValue(registrationVO.getRegistrationId());

            colIndex++;
        }

        // 10. 自动调整列宽
        for (int i = 0; i <= laneToTeamMap.size(); i++) {
            sheet.autoSizeColumn(i);
            // 获取当前列宽
            int currentWidth = sheet.getColumnWidth(i);
            // 增加额外宽度，例如增加 40% 的宽度
            int extraWidth = (int)(currentWidth * 0.4);
            sheet.setColumnWidth(i, currentWidth + extraWidth);
        }

        // 11. 写入文件
        try (FileOutputStream fos = new FileOutputStream(file)) {
            workbook.write(fos);
            workbook.close();
            showInfoDialog("导出成功！");
        } catch (IOException e) {
            e.printStackTrace();
            showErrorDialog("导出失败: " + e.getMessage());
        }
    }
}

